/**
 * @file client_request.h
 * @brief 客户端请求结构定义文件
 * 
 * @details 该文件定义了交易所系统中客户端请求的结构和类型，
 * 包括客户端请求类型、匹配引擎内部使用的客户端请求结构和
 * 网络传输的客户端请求结构。这些结构用于客户端和交易所之间的通信。
 * 
 * @author 原作者
 * @date 2023
 */

#pragma once

#include <sstream>

#include "common/types.h"
#include "common/lf_queue.h"

using namespace Common;

namespace Exchange {
  /**
   * @brief 客户端发送给交易所的订单请求类型
   * 
   * @details 定义了交易客户端可以发送给交易所的不同类型的请求，
   * 包括新建订单和取消订单等操作。
   */
  enum class ClientRequestType : uint8_t {
    INVALID = 0,  ///< 无效请求类型
    NEW = 1,      ///< 新建订单请求
    CANCEL = 2    ///< 取消订单请求
  };

  /**
   * @brief 将客户端请求类型转换为字符串表示
   * 
   * @details 该函数将ClientRequestType枚举值转换为其对应的字符串表示，
   * 主要用于日志记录和调试输出。
   * 
   * @param type 要转换的客户端请求类型
   * @return std::string 客户端请求类型的字符串表示
   */
  inline std::string clientRequestTypeToString(ClientRequestType type) {
    switch (type) {
      case ClientRequestType::NEW:
        return "NEW";
      case ClientRequestType::CANCEL:
        return "CANCEL";
      case ClientRequestType::INVALID:
        return "INVALID";
    }
    return "UNKNOWN"; // 处理未定义的枚举值
  }

  /**
   * @brief 二进制结构打包指令
   * 
   * @details 这些结构会通过网络传输，因此使用打包指令移除系统相关的额外填充，
   * 确保不同系统之间的二进制兼容性。
   */
#pragma pack(push, 1)

  /**
   * @brief 匹配引擎内部使用的客户端请求结构
   * 
   * @details 该结构定义了匹配引擎内部处理的客户端请求格式，
   * 包含请求类型、客户端ID、证券ID、订单ID、交易方向、价格和数量等信息。
   * 这些信息用于匹配引擎处理订单的创建和取消操作。
   */
  struct MEClientRequest {
    /**
     * @brief 客户端请求类型
     * 
     * @details 指定该请求是新建订单还是取消订单
     */
    ClientRequestType type_ = ClientRequestType::INVALID;

    ClientId client_id_ = ClientId_INVALID;   ///< 客户端ID，用于标识发送请求的客户端
    TickerId ticker_id_ = TickerId_INVALID;   ///< 证券ID，指定订单相关的证券
    OrderId order_id_ = OrderId_INVALID;      ///< 订单ID，用于标识特定订单
    Side side_ = Side::INVALID;               ///< 交易方向，买入或卖出
    Price price_ = Price_INVALID;            ///< 订单价格
    Qty qty_ = Qty_INVALID;                  ///< 订单数量

    /**
     * @brief 将客户端请求转换为字符串表示
     * 
     * @details 该方法将MEClientRequest结构的内容格式化为便于阅读的字符串，
     * 主要用于日志记录和调试输出。字符串包含请求类型、客户端ID、
     * 证券ID、订单ID、交易方向、数量和价格等信息。
     * 
     * @return std::string 请求的字符串表示
     */
    auto toString() const {
      std::stringstream ss;
      ss << "MEClientRequest"
         << " ["
         << "type:" << clientRequestTypeToString(type_)  // 请求类型
         << " client:" << clientIdToString(client_id_)  // 客户端ID
         << " ticker:" << tickerIdToString(ticker_id_)  // 证券ID
         << " oid:" << orderIdToString(order_id_)       // 订单ID
         << " side:" << sideToString(side_)             // 交易方向
         << " qty:" << qtyToString(qty_)                // 订单数量
         << " price:" << priceToString(price_)          // 订单价格
         << "]";
      return ss.str();
    }
  };

  /**
   * @brief 订单网关客户端通过网络发布的客户端请求结构
   * 
   * @details 该结构定义了订单网关客户端通过网络发送给交易所的请求格式。
   * 它包含一个序列号和一个匹配引擎客户端请求结构。序列号用于确保消息的可靠传输
   * 和按序处理，帮助检测消息丢失或乱序的情况。
   */
  struct OMClientRequest {
    size_t seq_num_ = 0;                ///< 序列号，用于确保消息的可靠传输和按序处理
    MEClientRequest me_client_request_; ///< 匹配引擎客户端请求结构，包含订单的具体信息

    /**
     * @brief 将订单网关客户端请求转换为字符串表示
     * 
     * @details 该方法将OMClientRequest结构的内容格式化为便于阅读的字符串，
     * 主要用于日志记录和调试输出。字符串包含序列号和内部MEClientRequest结构的字符串表示。
     * 
     * @return std::string 请求的字符串表示
     */
    auto toString() const {
      std::stringstream ss;
      ss << "OMClientRequest"
         << " ["
         << "seq:" << seq_num_                   // 序列号
         << " " << me_client_request_.toString() // 内部客户端请求结构
         << "]";
      return ss.str();
    }
  };

/**
   * @brief 取消二进制结构打包指令
   * 
   * @details 恢复默认的结构对齐方式，取消前面的打包指令对后续代码的影响。
   */
#pragma pack(pop) // Undo the packed binary structure directive moving forward.

  /**
   * @brief 匹配引擎客户端订单请求消息的无锁队列
   * 
   * @details 定义了一个存储MEClientRequest对象的无锁队列类型。
   * 该队列用于订单服务器和匹配引擎之间的通信，实现了高效的线程间数据传输。
   * 无锁队列确保了在多线程环境下的线程安全性，无需使用互斥锁或其他同步原语。
   */
  typedef LFQueue<MEClientRequest> ClientRequestLFQueue;
}
